#include "NcUtil.h"

namespace OCPP
{
	size_t NcUtil::getVarSize(const NcVar& var)
	{
		size_t size = 1;
		
		std::vector<NcDim> dims = var.getDims();
		for (const NcDim& d : dims)
		{
			size *= d.getSize();
		}
		return size;
	}

	FloatVector NcUtil::readFloat(const NcVar& var)
	{
		FloatVector data;

		try {
			NcType type = var.getType();
			size_t size = getVarSize(var);
			data.resize(size);
			if (type == NC_FLOAT)
			{
				var.getVar(&data[0]);
			}
			else if (type == NC_INT)
			{
				getTypeDataToFloat<IntVector>(data, var);
			}
			else if (type == NC_LONG)
			{
				getTypeDataToFloat<LongVector>(data, var);
			}
			else if (type == NC_UINT)
			{
				getTypeDataToFloat<Uint32Vector>(data, var);
			}
			else if (type == NC_USHORT)
			{
				getTypeDataToFloat<Uint16Vector>(data, var);
			}
			else if (type == NC_DOUBLE)
			{
				getTypeDataToFloat<DoubleVector>(data, var);
			}
		}
		catch (exceptions::NcException& e) {
			OCPP_LOG_ERROR << e.what() << "\n";
		}

		return data;
	}

	String NcUtil::readStringAttr(const NcAtt& attr)
	{
		String value;
		if (!attr.isNull())
		{
			auto type = attr.getType();
			String name = type.getName();
			if (type == netCDF::NcType::nc_STRING)
			{
				attr.getValues(&value);
			}	
			else if (type == netCDF::NcType::nc_CHAR)
			{
				size_t len = attr.getAttLength();
				value.resize(len + 1);
				attr.getValues(value.data());
			}
		}
		return value;
	}

	float NcUtil::readFloatAttr(const NcAtt& attr,float defaultValue)
	{
		float value = defaultValue;

		if (attr.getType() == netCDF::NcType::nc_FLOAT)
		{
			attr.getValues(&value);
		}
		else if (attr.getType() == netCDF::NcType::nc_DOUBLE)
		{
			double tmp;
			attr.getValues(&tmp);
			value = (float)tmp;
		}

		return value;
	}

	IntVector NcUtil::readInt(const NcVar& var)
	{
		IntVector data;
		try {
			NcType type = var.getType();
#if _DEBUG
			String name = type.getName();
			OCPP_LOG_INFO << name << "\n";
#endif
			size_t size = getVarSize(var);
			data.resize(size);
			if (type == NC_FLOAT)
			{
				getTypeDataToInt<FloatVector>(data, var);
			}
			else if (type == NC_INT)
			{
				data.resize(size);
				var.getVar(&data[0]);
			}
			else if (type == NC_LONG || type == NC_INT64 || type == NC_UINT64)
			{
				getTypeDataToInt<LongVector>(data, var);
			}
			else if (type == NC_UINT)
			{
				getTypeDataToInt<Uint32Vector>(data, var);
			}
			else if (type == NC_USHORT)
			{
				getTypeDataToInt<Uint16Vector>(data, var);
			}
			else if (type == NC_DOUBLE)
			{
				getTypeDataToInt<DoubleVector>(data, var);
			}
		}
		catch (exceptions::NcException& e) {
			OCPP_LOG_ERROR << e.what() << "\n";
		}
		return data;
	}

	inline bool inNameVec(const std::vector<String>& nameVec, String name)
	{
		StringUtil::toLowerCase(name);
		return std::find(nameVec.begin(), nameVec.end(), name) != nameVec.end();
	}

	bool NcUtil::isDimT(String name, const VolumeOptions& options)
	{
		StringUtil::toLowerCase(name);
		return inNameVec(options.nameDimT, name) || StringUtil::contains(name, "time", false);
	}

	bool NcUtil::isDimZ(String name, const VolumeOptions& options)
	{
		StringUtil::toLowerCase(name);
		return inNameVec(options.nameDimZ, name) || StringUtil::contains(name, "level", false);
	}

	bool NcUtil::isDimY(String name, const VolumeOptions& options)
	{
		StringUtil::toLowerCase(name);
		return inNameVec(options.nameDimY, name);
	}

	bool NcUtil::isDimX(String name, const VolumeOptions& options)
	{
		StringUtil::toLowerCase(name);
		return inNameVec(options.nameDimX, name);
	}
}


